1 /**
  2  * 测试用例库文件,提供如event mock、iframe封装等各种常用功能 部分方法来源于YUI测试框架
  3  */
  4 UserAction = {
  5     beforedispatch:null,
  6 //    flag : true,
  7     isf /* is function ? */:function ( value ) {
  8         return value && (typeof value == 'function');
  9     },
 10     isb /* is boolean? */:function ( value ) {
 11         return value && (typeof value == 'boolean');
 12     },
 13     iso /* is object? */:function ( value ) {
 14         return value && (typeof value == 'object');
 15     },
 16     iss /* is string? */:function ( value ) {
 17         return value && (typeof value == 'string');
 18     },
 19     isn /* is number? */:function ( value ) {
 20         return value && (typeof value == 'number');
 21     },
 22     // --------------------------------------------------------------------------
 23     // Generic event methods
 24     // --------------------------------------------------------------------------
 25 
 26     /**
 27      * Simulates a key event using the given event information to populate the
 28      * generated event object. This method does browser-equalizing calculations
 29      * to account for differences in the DOM and IE event models as well as
 30      * different browser quirks. Note: keydown causes Safari 2.x to crash.
 31      *
 32      * @method simulateKeyEvent
 33      * @private
 34      * @static
 35      * @param {HTMLElement}
 36         *            target The target of the given event.
 37      * @param {String}
 38         *            type The type of event to fire. This can be any one of the
 39      *            following: keyup, keydown, and keypress.
 40      * @param {Boolean}
 41         *            bubbles (Optional) Indicates if the event can be bubbled up.
 42      *            DOM Level 3 specifies that all key events bubble by default.
 43      *            The default is true.
 44      * @param {Boolean}
 45         *            cancelable (Optional) Indicates if the event can be canceled
 46      *            using preventDefault(). DOM Level 3 specifies that all key
 47      *            events can be cancelled. The default is true.
 48      * @param {Window}
 49         *            view (Optional) The view containing the target. This is
 50      *            typically the window object. The default is window.
 51      * @param {Boolean}
 52         *            ctrlKey (Optional) Indicates if one of the CTRL keys is
 53      *            pressed while the event is firing. The default is false.
 54      * @param {Boolean}
 55         *            altKey (Optional) Indicates if one of the ALT keys is pressed
 56      *            while the event is firing. The default is false.
 57      * @param {Boolean}
 58         *            shiftKey (Optional) Indicates if one of the SHIFT keys is
 59      *            pressed while the event is firing. The default is false.
 60      * @param {Boolean}
 61         *            metaKey (Optional) Indicates if one of the META keys is
 62      *            pressed while the event is firing. The default is false.
 63      * @param {int}
 64         *            keyCode (Optional) The code for the key that is in use. The
 65      *            default is 0.
 66      * @param {int}
 67         *            charCode (Optional) The Unicode code for the character
 68      *            associated with the key being used. The default is 0.
 69      */
 70     simulateKeyEvent:function ( target /* :HTMLElement */, type /* :String */, bubbles /* :Boolean */, cancelable /* :Boolean */, view /* :Window */, ctrlKey /* :Boolean */, altKey /* :Boolean */, shiftKey /* :Boolean */, metaKey /* :Boolean */, keyCode /* :int */, charCode /* :int */ ) /* :Void */ {
 71         // check target
 72         target = typeof target == 'string' ? document.getElementById( target )
 73             : target;
 74         if ( !target ) {
 75             throw new Error( "simulateKeyEvent(): Invalid target." );
 76         }
 77 
 78         // check event type
 79         if ( typeof type == 'string' ) {
 80             type = type.toLowerCase();
 81             switch ( type ) {
 82                 case "keyup":
 83                 case "keydown":
 84                 case "keypress":
 85                     break;
 86                 case "textevent": // DOM Level 3
 87                     type = "keypress";
 88                     break;
 89                 // @TODO was the fallthrough intentional, if so throw error
 90                 default:
 91                     throw new Error( "simulateKeyEvent(): Event type '" + type
 92                         + "' not supported." );
 93             }
 94         } else {
 95             throw new Error( "simulateKeyEvent(): Event type must be a string." );
 96         }
 97 
 98         // setup default values
 99         if ( !this.isb( bubbles ) ) {
100             bubbles = true; // all key events bubble
101         }
102         if ( !this.isb( cancelable ) ) {
103             cancelable = true; // all key events can be cancelled
104         }
105         if ( !this.iso( view ) ) {
106             view = window; // view is typically window
107         }
108         if ( !this.isb( ctrlKey ) ) {
109             ctrlKey = false;
110         }
111         if ( !this.isb( typeof altKey == 'boolean' ) ) {
112             altKey = false;
113         }
114         if ( !this.isb( shiftKey ) ) {
115             shiftKey = false;
116         }
117         if ( !this.isb( metaKey ) ) {
118             metaKey = false;
119         }
120         if ( !(typeof keyCode == 'number') ) {
121             keyCode = 0;
122         }
123         if ( !(typeof charCode == 'number') ) {
124             charCode = 0;
125         }
126 
127         // try to create a mouse event
128         var customEvent /* :MouseEvent */ = null;
129 
130         // check for DOM-compliant browsers first
131         if ( this.isf( document.createEvent ) ) {
132 
133             try {
134 
135                 // try to create key event
136                 customEvent = document.createEvent( "KeyEvents" );
137 
138                 /*
139                  * Interesting problem: Firefox implemented a non-standard
140                  * version of initKeyEvent() based on DOM Level 2 specs. Key
141                  * event was removed from DOM Level 2 and re-introduced in DOM
142                  * Level 3 with a different interface. Firefox is the only
143                  * browser with any implementation of Key Events, so for now,
144                  * assume it's Firefox if the above line doesn't error.
145                  */
146                 // TODO: Decipher between Firefox's implementation and a correct
147                 // one.
148                 customEvent.initKeyEvent( type, bubbles, cancelable, view,
149                     ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode );
150 
151             } catch ( ex /* :Error */ ) {
152 
153                 /*
154                  * If it got here, that means key events aren't officially
155                  * supported. Safari/WebKit is a real problem now. WebKit 522
156                  * won't let you set keyCode, charCode, or other properties if
157                  * you use a UIEvent, so we first must try to create a generic
158                  * event. The fun part is that this will throw an error on
159                  * Safari 2.x. The end result is that we need another
160                  * try...catch statement just to deal with this mess.
161                  */
162                 try {
163 
164                     // try to create generic event - will fail in Safari 2.x
165                     customEvent = document.createEvent( "Events" );
166 
167                 } catch ( uierror /* :Error */ ) {
168 
169                     // the above failed, so create a UIEvent for Safari 2.x
170                     customEvent = document.createEvent( "UIEvents" );
171 
172                 } finally {
173 
174                     customEvent.initEvent( type, bubbles, cancelable );
175 
176                     // initialize
177                     customEvent.view = view;
178                     customEvent.altKey = altKey;
179                     customEvent.ctrlKey = ctrlKey;
180                     customEvent.shiftKey = shiftKey;
181                     customEvent.metaKey = metaKey;
182                     customEvent.keyCode = keyCode;
183                     customEvent.charCode = charCode;
184 
185                 }
186 
187             }
188 
189             // before dispatch
190             if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
191                 this.beforedispatch( customEvent );
192             this.beforedispatch = null;
193 
194             // fire the event
195             target.dispatchEvent( customEvent );
196 
197         } else if ( this.iso( document.createEventObject ) ) { // IE
198 
199             // create an IE event object
200             customEvent = document.createEventObject();
201 
202             // assign available properties
203             customEvent.bubbles = bubbles;
204             customEvent.cancelable = cancelable;
205             customEvent.view = view;
206             customEvent.ctrlKey = ctrlKey;
207             customEvent.altKey = altKey;
208             customEvent.shiftKey = shiftKey;
209             customEvent.metaKey = metaKey;
210 
211             /*
212              * IE doesn't support charCode explicitly. CharCode should take
213              * precedence over any keyCode value for accurate representation.
214              */
215             customEvent.keyCode = (charCode > 0) ? charCode : keyCode;
216 
217             // before dispatch
218             if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
219                 this.beforedispatch( customEvent );
220             this.beforedispatch = null;
221 
222             // fire the event
223             target.fireEvent( "on" + type, customEvent );
224 
225         } else {
226             throw new Error(
227                 "simulateKeyEvent(): No event simulation framework present." );
228         }
229 
230         this.beforedispatch = null;
231     },
232 
233     /**
234      * Simulates a mouse event using the given event information to populate the
235      * generated event object. This method does browser-equalizing calculations
236      * to account for differences in the DOM and IE event models as well as
237      * different browser quirks.
238      *
239      * @method simulateMouseEvent
240      * @private
241      * @static
242      * @param {HTMLElement}
243         *            target The target of the given event.
244      * @param {String}
245         *            type The type of event to fire. This can be any one of the
246      *            following: click, dblclick, mousedown, mouseup, mouseout,
247      *            mouseover, and mousemove.
248      * @param {Boolean}
249         *            bubbles (Optional) Indicates if the event can be bubbled up.
250      *            DOM Level 2 specifies that all mouse events bubble by default.
251      *            The default is true.
252      * @param {Boolean}
253         *            cancelable (Optional) Indicates if the event can be canceled
254      *            using preventDefault(). DOM Level 2 specifies that all mouse
255      *            events except mousemove can be cancelled. The default is true
256      *            for all events except mousemove, for which the default is
257      *            false.
258      * @param {Window}
259         *            view (Optional) The view containing the target. This is
260      *            typically the window object. The default is window.
261      * @param {int}
262         *            detail (Optional) The number of times the mouse button has
263      *            been used. The default value is 1.
264      * @param {int}
265         *            screenX (Optional) The x-coordinate on the screen at which
266      *            point the event occured. The default is 0.
267      * @param {int}
268         *            screenY (Optional) The y-coordinate on the screen at which
269      *            point the event occured. The default is 0.
270      * @param {int}
271         *            clientX (Optional) The x-coordinate on the client at which
272      *            point the event occured. The default is 0.
273      * @param {int}
274         *            clientY (Optional) The y-coordinate on the client at which
275      *            point the event occured. The default is 0.
276      * @param {Boolean}
277         *            ctrlKey (Optional) Indicates if one of the CTRL keys is
278      *            pressed while the event is firing. The default is false.
279      * @param {Boolean}
280         *            altKey (Optional) Indicates if one of the ALT keys is pressed
281      *            while the event is firing. The default is false.
282      * @param {Boolean}
283         *            shiftKey (Optional) Indicates if one of the SHIFT keys is
284      *            pressed while the event is firing. The default is false.
285      * @param {Boolean}
286         *            metaKey (Optional) Indicates if one of the META keys is
287      *            pressed while the event is firing. The default is false.
288      * @param {int}
289         *            button (Optional) The button being pressed while the event is
290      *            executing. The value should be 0 for the primary mouse button
291      *            (typically the left button), 1 for the terciary mouse button
292      *            (typically the middle button), and 2 for the secondary mouse
293      *            button (typically the right button). The default is 0.
294      * @param {HTMLElement}
295         *            relatedTarget (Optional) For mouseout events, this is the
296      *            element that the mouse has moved to. For mouseover events,
297      *            this is the element that the mouse has moved from. This
298      *            argument is ignored for all other events. The default is null.
299      */
300     simulateMouseEvent:function ( target /* :HTMLElement */, type /* :String */, bubbles /* :Boolean */, cancelable /* :Boolean */, view /* :Window */, detail /* :int */, screenX /* :int */, screenY /* :int */, clientX /* :int */, clientY /* :int */, ctrlKey /* :Boolean */, altKey /* :Boolean */, shiftKey /* :Boolean */, metaKey /* :Boolean */, button /* :int */, relatedTarget /* :HTMLElement */ ) /* :Void */ {
301 
302         // check target
303         target = typeof target == 'string' ? document.getElementById( target )
304             : target;
305         if ( !target ) {
306             throw new Error( "simulateMouseEvent(): Invalid target." );
307         }
308 
309         // check event type
310         if ( this.iss( type ) ) {
311             type = type.toLowerCase();
312             switch ( type ) {
313                 case "mouseover":
314                 case "mouseout":
315                 case "mousedown":
316                 case "mouseup":
317                 case "click":
318                 case "dblclick":
319                 case "mousemove":
320                 case "mouseenter":// 非标准支持,仅为测试提供,该项仅IE下work
321                 case "mouseleave":
322                     break;
323                 default:
324                     throw new Error( "simulateMouseEvent(): Event type '" + type
325                         + "' not supported." );
326             }
327         } else {
328             throw new Error(
329                 "simulateMouseEvent(): Event type must be a string." );
330         }
331 
332         // setup default values
333         if ( !this.isb( bubbles ) ) {
334             bubbles = true; // all mouse events bubble
335         }
336         if ( !this.isb( cancelable ) ) {
337             cancelable = (type != "mousemove"); // mousemove is the only one
338             // that can't be cancelled
339         }
340         if ( !this.iso( view ) ) {
341             view = window; // view is typically window
342         }
343         if ( !this.isn( detail ) ) {
344             detail = 1; // number of mouse clicks must be at least one
345         }
346         if ( !this.isn( screenX ) ) {
347             screenX = 0;
348         }
349         if ( !this.isn( screenY ) ) {
350             screenY = 0;
351         }
352         if ( !this.isn( clientX ) ) {
353             clientX = 0;
354         }
355         if ( !this.isn( clientY ) ) {
356             clientY = 0;
357         }
358         if ( !this.isb( ctrlKey ) ) {
359             ctrlKey = false;
360         }
361         if ( !this.isb( altKey ) ) {
362             altKey = false;
363         }
364         if ( !this.isb( shiftKey ) ) {
365             shiftKey = false;
366         }
367         if ( !this.isb( metaKey ) ) {
368             metaKey = false;
369         }
370         if ( !this.isn( button ) ) {
371             button = 0;
372         }
373 
374         // try to create a mouse event
375         var customEvent /* :MouseEvent */ = null;
376 
377         // check for DOM-compliant browsers first
378         if ( this.isf( document.createEvent ) ) {
379 
380             customEvent = document.createEvent( "MouseEvents" );
381 
382             // Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
383             if ( this.browser.ie !== 9 && customEvent.initMouseEvent ) {
384                 customEvent.initMouseEvent( type, bubbles, cancelable, view,
385                     detail, screenX, screenY, clientX, clientY, ctrlKey,
386                     altKey, shiftKey, metaKey, button, relatedTarget );
387             } else { // Safari
388 
389                 // the closest thing available in Safari 2.x is UIEvents
390                 customEvent = document.createEvent( "UIEvents" );
391                 customEvent.initEvent( type, bubbles, cancelable );
392                 customEvent.view = view;
393                 customEvent.detail = detail;
394                 customEvent.screenX = screenX;
395                 customEvent.screenY = screenY;
396                 customEvent.clientX = clientX;
397                 customEvent.clientY = clientY;
398                 customEvent.ctrlKey = ctrlKey;
399                 customEvent.altKey = altKey;
400                 customEvent.metaKey = metaKey;
401                 customEvent.shiftKey = shiftKey;
402                 customEvent.button = button;
403                 customEvent.relatedTarget = relatedTarget;
404             }
405 
406             /*
407              * Check to see if relatedTarget has been assigned. Firefox versions
408              * less than 2.0 don't allow it to be assigned via initMouseEvent()
409              * and the property is readonly after event creation, so in order to
410              * keep YAHOO.util.getRelatedTarget() working, assign to the IE
411              * proprietary toElement property for mouseout event and fromElement
412              * property for mouseover event.
413              */
414             if ( relatedTarget && !customEvent.relatedTarget ) {
415                 if ( type == "mouseout" ) {
416                     customEvent.toElement = relatedTarget;
417                 } else if ( type == "mouseover" ) {
418                     customEvent.fromElement = relatedTarget;
419                 }
420             }
421 
422             // before dispatch
423             if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
424                 this.beforedispatch( customEvent );
425             this.beforedispatch = null;
426 
427             // fire the event
428             target.dispatchEvent( customEvent );
429 
430         } else if ( this.iso( document.createEventObject ) ) { // IE
431 
432             // create an IE event object
433             customEvent = document.createEventObject();
434 
435             // assign available properties
436             customEvent.bubbles = bubbles;
437             customEvent.cancelable = cancelable;
438             customEvent.view = view;
439             customEvent.detail = detail;
440             customEvent.screenX = screenX;
441             customEvent.screenY = screenY;
442             customEvent.clientX = clientX;
443             customEvent.clientY = clientY;
444             customEvent.ctrlKey = ctrlKey;
445             customEvent.altKey = altKey;
446             customEvent.metaKey = metaKey;
447             customEvent.shiftKey = shiftKey;
448 
449             // fix button property for IE's wacky implementation
450             switch ( button ) {
451                 case 0:
452                     customEvent.button = 1;
453                     break;
454                 case 1:
455                     customEvent.button = 4;
456                     break;
457                 case 2:
458                     // leave as is
459                     break;
460                 default:
461                     customEvent.button = 0;
462             }
463 
464             /*
465              * Have to use relatedTarget because IE won't allow assignment to
466              * toElement or fromElement on generic events. This keeps
467              * YAHOO.util.customEvent.getRelatedTarget() functional.
468              */
469             customEvent.relatedTarget = relatedTarget;
470 
471             // before dispatch
472             if ( this.beforedispatch && typeof this.beforedispatch == 'function' )
473                 this.beforedispatch( customEvent );
474             this.beforedispatch = null;
475             // fire the event
476             target.fireEvent( "on" + type, customEvent );
477 
478         } else {
479             throw new Error(
480                 "simulateMouseEvent(): No event simulation framework present." );
481         }
482     },
483 
484     // --------------------------------------------------------------------------
485     // Mouse events
486     // --------------------------------------------------------------------------
487 
488     /**
489      * Simulates a mouse event on a particular element.
490      *
491      * @param {HTMLElement}
492         *            target The element to click on.
493      * @param {String}
494         *            type The type of event to fire. This can be any one of the
495      *            following: click, dblclick, mousedown, mouseup, mouseout,
496      *            mouseover, and mousemove.
497      * @param {Object}
498         *            options Additional event options (use DOM standard names).
499      * @method mouseEvent
500      * @static
501      */
502     fireMouseEvent:function ( target /* :HTMLElement */, type /* :String */, options /* :Object */ ) /* :Void */ {
503         options = options || {};
504         this.simulateMouseEvent( target, type, options.bubbles,
505             options.cancelable, options.view, options.detail,
506             options.screenX, options.screenY, options.clientX,
507             options.clientY, options.ctrlKey, options.altKey,
508             options.shiftKey, options.metaKey, options.button,
509             options.relatedTarget );
510     },
511 
512     /**
513      * Simulates a click on a particular element.
514      *
515      * @param {HTMLElement}
516         *            target The element to click on.
517      * @param {Object}
518         *            options Additional event options (use DOM standard names).
519      * @method click
520      * @static
521      */
522     click:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
523         this.fireMouseEvent( target, "click", options );
524     },
525 
526     /**
527      * Simulates a double click on a particular element.
528      *
529      * @param {HTMLElement}
530         *            target The element to double click on.
531      * @param {Object}
532         *            options Additional event options (use DOM standard names).
533      * @method dblclick
534      * @static
535      */
536     dblclick:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
537         this.fireMouseEvent( target, "dblclick", options );
538     },
539 
540     /**
541      * Simulates a mousedown on a particular element.
542      *
543      * @param {HTMLElement}
544         *            target The element to act on.
545      * @param {Object}
546         *            options Additional event options (use DOM standard names).
547      * @method mousedown
548      * @static
549      */
550     mousedown:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
551         this.fireMouseEvent( target, "mousedown", options );
552     },
553 
554     /**
555      * Simulates a mousemove on a particular element.
556      *
557      * @param {HTMLElement}
558         *            target The element to act on.
559      * @param {Object}
560         *            options Additional event options (use DOM standard names).
561      * @method mousemove
562      * @static
563      */
564     mousemove:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
565         this.fireMouseEvent( target, "mousemove", options );
566     },
567 
568     /**
569      * Simulates a mouseout event on a particular element. Use "relatedTarget"
570      * on the options object to specify where the mouse moved to. Quirks:
571      * Firefox less than 2.0 doesn't set relatedTarget properly, so toElement is
572      * assigned in its place. IE doesn't allow toElement to be be assigned, so
573      * relatedTarget is assigned in its place. Both of these concessions allow
574      * YAHOO.util.Event.getRelatedTarget() to work correctly in both browsers.
575      *
576      * @param {HTMLElement}
577         *            target The element to act on.
578      * @param {Object}
579         *            options Additional event options (use DOM standard names).
580      * @method mouseout
581      * @static
582      */
583     mouseout:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
584         this.fireMouseEvent( target, "mouseout", options );
585     },
586 
587     /**
588      * Simulates a mouseover event on a particular element. Use "relatedTarget"
589      * on the options object to specify where the mouse moved from. Quirks:
590      * Firefox less than 2.0 doesn't set relatedTarget properly, so fromElement
591      * is assigned in its place. IE doesn't allow fromElement to be be assigned,
592      * so relatedTarget is assigned in its place. Both of these concessions
593      * allow YAHOO.util.Event.getRelatedTarget() to work correctly in both
594      * browsers.
595      *
596      * @param {HTMLElement}
597         *            target The element to act on.
598      * @param {Object}
599         *            options Additional event options (use DOM standard names).
600      * @method mouseover
601      * @static
602      */
603     mouseover:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
604         this.fireMouseEvent( target, "mouseover", options );
605     },
606 
607     /**
608      * Simulates a mouseup on a particular element.
609      *
610      * @param {HTMLElement}
611         *            target The element to act on.
612      * @param {Object}
613         *            options Additional event options (use DOM standard names).
614      * @method mouseup
615      * @static
616      */
617     mouseup:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
618         this.fireMouseEvent( target, "mouseup", options );
619     },
620 
621     dragto:function ( target, options ) {
622         var me = this;
623         me.mousemove( target, {
624             clientX:options.startX,
625             clientY:options.startY
626         } );
627         setTimeout( function () {
628             me.mousedown( target, {
629                 clientX:options.startX,
630                 clientY:options.startY
631             } );
632             setTimeout( function () {
633                 me.mousemove( target, {
634                     clientX:options.endX,
635                     clientY:options.endY
636                 } );
637                 setTimeout( function () {
638                     me.mouseup( target, {
639                         clientX:options.endX,
640                         clientY:options.endY
641                     } );
642                     if ( options.callback )
643                         options.callback();
644                 }, options.aftermove || 20 );
645             }, options.beforemove || 20 );
646         }, options.beforestart || 50 );
647     },
648 
649     // --------------------------------------------------------------------------
650     // Key events
651     // --------------------------------------------------------------------------
652 
653     /**
654      * Fires an event that normally would be fired by the keyboard (keyup,
655      * keydown, keypress). Make sure to specify either keyCode or charCode as an
656      * option.
657      *
658      * @private
659      * @param {String}
660         *            type The type of event ("keyup", "keydown" or "keypress").
661      * @param {HTMLElement}
662         *            target The target of the event.
663      * @param {Object}
664         *            options Options for the event. Either keyCode or charCode are
665      *            required.
666      * @method fireKeyEvent
667      * @static
668      */
669     fireKeyEvent:function ( type /* :String */, target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
670         options = options || {};
671         this.simulateKeyEvent( target, type, options.bubbles,
672             options.cancelable, options.view, options.ctrlKey,
673             options.altKey, options.shiftKey, options.metaKey,
674             options.keyCode, options.charCode );
675     },
676 
677     /**
678      * Simulates a keydown event on a particular element.
679      *
680      * @param {HTMLElement}
681         *            target The element to act on.
682      * @param {Object}
683         *            options Additional event options (use DOM standard names).
684      * @method keydown
685      * @static
686      */
687     keydown:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
688         this.fireKeyEvent( "keydown", target, options );
689     },
690 
691     /**
692      * Simulates a keypress on a particular element.
693      *
694      * @param {HTMLElement}
695         *            target The element to act on.
696      * @param {Object}
697         *            options Additional event options (use DOM standard names).
698      * @method keypress
699      * @static
700      */
701     keypress:function ( target /* :HTMLElement */, options /* :Object */ ) /* :Void */ {
702         this.fireKeyEvent( "keypress", target, options );
703     },
704 
705     /**
706      * Simulates a keyup event on a particular element.
707      *
708      * @param {HTMLElement}
709         *            target The element to act on.
710      * @param {Object}
711         *            options Additional event options (use DOM standard names).
712      * @method keyup
713      * @static
714      */
715     keyup:function ( target /* :HTMLElement */, options /* Object */ ) /* :Void */ {
716         this.fireKeyEvent( "keyup", target, options );
717     },
718 
719     /**
720      * 提供iframe扩展支持,用例测试需要独立场景的用例,由于异步支持,通过finish方法触发start
721      * <li>事件绑定在frame上,包括afterfinish和jsloaded
722      *
723      * @param op.win
724      * @param op.nojs
725      *            不加载额外js
726      * @param op.ontest
727      *            测试步骤
728      * @param op.onbeforestart
729      *            测试启动前处理步骤,默认为QUnit.stop();
730      * @param op.onafterfinish
731      *            测试完毕执行步骤,默认为QUnit.start()
732      *
733      */
734     frameExt:function ( op ) {
735         stop();
736         op = typeof op == 'function' ? {
737             ontest:op
738         } : op;
739         var pw = op.win || window, w, f, url = '', id = typeof op.id == 'undefined' ? 'f'
740             : op.id, fid = 'iframe#' + id;
741 
742         op.finish = function () {
743             pw.$( fid ).unbind();
744             setTimeout( function () {
745                 pw.$( 'div#div' + id ).remove();
746                 start();
747             }, 20 );
748         };
749 
750         if ( pw.$( fid ).length == 0 ) {
751             /* 添加frame,部分情况下,iframe没有边框,为了可以看到效果,添加一个带边框的div */
752             pw.$( pw.document.body ).append( '<div id="div' + id + '"></div>' );
753             pw.$( 'div#div' + id ).append( '<iframe id="' + id + '"></iframe>' );
754         }
755         op.onafterstart && op.onafterstart( $( 'iframe#f' )[0] );
756         pw.$( 'script' ).each( function () {
757             if ( this.src && this.src.indexOf( 'import.php' ) >= 0 ) {
758                 url = this.src.split( 'import.php' )[1];
759             }
760         } );
761         pw.$( fid ).one( 'load',
762             function ( e ) {
763                 var w = e.target.contentWindow;
764                 var h = setInterval( function () {
765                     if ( w.baidu ) {// 等待加载完成,IE6下这地方总出问题
766                         clearInterval( h );
767                         op.ontest( w, w.frameElement );
768                     }
769                 }, 20 );
770                 // 找到当前操作的iframe,然后call ontest
771             } ).attr( 'src', cpath + 'frame.php' + url );
772     },
773 
774     /**
775      *
776      * 判断2个数组是否相等
777      *
778      * @static
779      */
780     isEqualArray:function ( array1, array2 ) {
781         if ( '[object Array]' != Object.prototype.toString.call( array1 )
782             || '[object Array]' != Object.prototype.toString.call( array2 ) )
783             return (array1 === array2);
784         else if ( array1.length != array2.length )
785             return false;
786         else {
787             for ( var i in array1 ) {
788                 if ( array1[i] != array2[i] )
789                     return false;
790             }
791             return true;
792         }
793     },
794 
795     /***************************************************************************
796      *
797      * 通用数据模块
798      *
799      * @static
800      *
801      **************************************************************************/
802     commonData:{// 针对测试文件的路径而不是UserAction的路径
803         "testdir":'../../',
804         datadir:(function () {
805             return location.href.split( "/_test/" )[0] + "/_test/tools/data/";
806         })(),
807         currentPath:function () {
808             var params = location.search.substring( 1 ).split( '&' );
809             for ( var i = 0; i < params.length; i++ ) {
810                 var p = params[i];
811                 if ( p.split( '=' )[0] == 'case' ) {
812                     var casepath = p.split( '=' )[1].split( '.' ).join( '/' );
813                     return location.href.split( '/_test/' )[0] + '/_test/'
814                         + casepath.substring( 0, casepath.lastIndexOf( '/' ) )
815                         + '/';
816                 }
817             }
818             return "";
819         }
820     },
821 
822     importsrc:function ( src, callback, matcher, exclude, win ) {
823         win = win || window;
824         var doc = win.document;
825 
826         var srcpath = location.href.split( "/_test/" )[0]
827             + "/_test/tools/br/import.php";
828         var param0 = src;
829         var ps = {
830             f:src
831         };
832         if ( exclude )
833             ps.e = exclude;
834         var param1 = exclude || "";
835         /**
836          * IE下重复载入会出现无法执行情况
837          */
838         if ( win.execScript ) {
839             $.get( srcpath, ps, function ( data ) {
840                 win.execScript( data );
841             } );
842         } else {
843             var head = doc.getElementsByTagName( 'head' )[0];
844             var sc = doc.createElement( 'script' );
845             sc.type = 'text/javascript';
846             sc.src = srcpath + "?f=" + param0 + "&e=" + param1;
847             head.appendChild( sc );
848         }
849 
850         matcher = matcher || src;
851         var mm = matcher.split( "," )[0].split( "." );
852         var h = setInterval( function () {
853             var p = win;
854             for ( var i = 0; i < mm.length; i++ ) {
855                 if ( typeof (p[mm[i]]) == 'undefined' ) {
856                     // console.log(mm[i]);
857                     return;
858                 }
859                 p = p[mm[i]];
860             }
861             clearInterval( h );
862             if ( callback && 'function' == typeof callback )
863                 callback();
864         }, 20 );
865     },
866 
867     /* 用于加载css文件,如果没有加载完毕则不执行回调函数 */
868     loadcss:function ( url, callback, classname, style, value ) {
869         var links = document.getElementsByTagName( 'link' );
870         for ( var link in links ) {
871             if ( link.href == url ) {
872                 callback();
873                 return;
874             }
875         }
876         var head = document.getElementsByTagName( 'head' )[0];
877         var link = head.appendChild( document.createElement( 'link' ) );
878         link.setAttribute( "rel", "stylesheet" );
879         link.setAttribute( "type", "text/css" );
880         link.setAttribute( "href", url );
881         var div = document.body.appendChild( document.createElement( "div" ) );
882         $( document ).ready(
883             function () {
884                 div.className = classname || 'cssloaded';
885                 var h = setInterval( function () {
886                     if ( $( div ).css( style || 'width' ) == value
887                         || $( div ).css( style || 'width' ) == '20px' ) {
888                         clearInterval( h );
889                         document.body.removeChild( div );
890                         setTimeout( callback, 20 );
891                     }
892                 }, 20 );
893             } );
894     },
895 
896     /**
897      * options supported
898      */
899     delayhelper:function ( oncheck, onsuccess, onfail, timeout ) {
900         onsuccess = onsuccess || oncheck.onsuccess;
901         onfail = onfail || oncheck.onfail || function () {
902             window.QUnit.fail( 'timeout wait for timeout : ' + timeout + 'ms' );
903             start();
904         };
905         timeout = timeout || oncheck.timeout || 10000;
906 
907         oncheck = (typeof oncheck == 'function') ? oncheck : oncheck.oncheck;
908         var h1 = setInterval( function () {
909             if ( !oncheck() )
910                 return;
911             else {
912                 clearInterval( h1 );
913                 clearTimeout( h2 );
914                 typeof onsuccess == "function" && onsuccess();
915             }
916         }, 20 );
917         var h2 = setTimeout( function () {
918             clearInterval( h1 );
919             clearTimeout( h2 );
920             onfail();
921         }, timeout );
922     },
923 
924     browser:(function () {
925         var win = window;
926 
927         var numberify = function ( s ) {
928             var c = 0;
929             return parseFloat( s.replace( /\./g, function () {
930                 return (c++ == 1) ? '' : '.';
931             } ) );
932         },
933 
934             nav = win && win.navigator,
935 
936             o = {
937 
938                 /**
939                  * Internet Explorer version number or 0. Example: 6
940                  *
941                  * @property ie
942                  * @type float
943                  * @static
944                  */
945                 ie:0,
946 
947                 /**
948                  * Opera version number or 0. Example: 9.2
949                  *
950                  * @property opera
951                  * @type float
952                  * @static
953                  */
954                 opera:0,
955 
956                 /**
957                  * Gecko engine revision number. Will evaluate to 1 if Gecko is
958                  * detected but the revision could not be found. Other browsers will
959                  * be 0. Example: 1.8
960                  *
961                  * <pre>
962                  * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
963                  * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
964                  * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
965                  * Firefox 3.0   <-- 1.9
966                  * Firefox 3.5   <-- 1.91
967                  * </pre>
968                  *
969                  * @property gecko
970                  * @type float
971                  * @static
972                  */
973                 gecko:0,
974 
975                 /**
976                  * AppleWebKit version. KHTML browsers that are not WebKit browsers
977                  * will evaluate to 1, other browsers 0. Example: 418.9
978                  *
979                  * <pre>
980                  * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
981                  *                                   latest available for Mac OSX 10.3.
982                  * Safari 2.0.2:         416     <-- hasOwnProperty introduced
983                  * Safari 2.0.4:         418     <-- preventDefault fixed
984                  * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
985                  *                                   different versions of webkit
986                  * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
987                  *                                   updated, but not updated
988                  *                                   to the latest patch.
989                  * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
990                  *                                   and many major issues fixed).
991                  * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic update
992                  *                                   from 2.x via the 10.4.11 OS patch
993                  * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
994                  *                                   yahoo.com user agent hack removed.
995                  * </pre>
996                  *
997                  * http://en.wikipedia.org/wiki/Safari_version_history
998                  *
999                  * @property webkit
1000                  * @type float
1001                  * @static
1002                  */
1003                 webkit:0,
1004 
1005                 /**
1006                  * Chrome will be detected as webkit, but this property will also be
1007                  * populated with the Chrome version number
1008                  *
1009                  * @property chrome
1010                  * @type float
1011                  * @static
1012                  */
1013                 chrome:0,
1014 
1015                 safari:0,
1016 
1017                 firefox:0,
1018 
1019                 maxthon:0,
1020                 maxthonIE:0,
1021 
1022                 /**
1023                  * The mobile property will be set to a string containing any
1024                  * relevant user agent information when a modern mobile browser is
1025                  * detected. Currently limited to Safari on the iPhone/iPod Touch,
1026                  * Nokia N-series devices with the WebKit-based browser, and Opera
1027                  * Mini.
1028                  *
1029                  * @property mobile
1030                  * @type string
1031                  * @static
1032                  */
1033                 mobile:null,
1034 
1035                 /**
1036                  * Adobe AIR version number or 0. Only populated if webkit is
1037                  * detected. Example: 1.0
1038                  *
1039                  * @property air
1040                  * @type float
1041                  */
1042                 air:0,
1043 
1044                 /**
1045                  * Google Caja version number or 0.
1046                  *
1047                  * @property caja
1048                  * @type float
1049                  */
1050                 caja:nav && nav.cajaVersion,
1051 
1052                 /**
1053                  * Set to true if the pagebreak appears to be in SSL
1054                  *
1055                  * @property secure
1056                  * @type boolean
1057                  * @static
1058                  */
1059                 secure:false,
1060 
1061                 /**
1062                  * The operating system. Currently only detecting windows or
1063                  * macintosh
1064                  *
1065                  * @property os
1066                  * @type string
1067                  * @static
1068                  */
1069                 os:null
1070 
1071             },
1072 
1073             ua = nav && nav.userAgent,
1074 
1075             loc = win && win.location,
1076 
1077             href = loc && loc.href,
1078 
1079             m;
1080 
1081         o.secure = href && (href.toLowerCase().indexOf( "https" ) === 0);
1082 
1083         if ( ua ) {
1084 
1085             if ( (/windows|win32/i).test( ua ) ) {
1086                 o.os = 'windows';
1087             } else if ( (/macintosh/i).test( ua ) ) {
1088                 o.os = 'macintosh';
1089             } else if ( (/rhino/i).test( ua ) ) {
1090                 o.os = 'rhino';
1091             }
1092 
1093             // Modern KHTML browsers should qualify as Safari X-Grade
1094             if ( (/KHTML/).test( ua ) ) {
1095                 o.webkit = 1;
1096             }
1097             if ( window.external && /(\d+\.\d)/.test( external.max_version ) ) {
1098 
1099                 o.maxthon = parseFloat( RegExp['\x241'] );
1100                 if ( /MSIE/.test( ua ) ) {
1101                     o.maxthonIE = 1;
1102                     o.maxthon = 0;
1103                 }
1104 
1105             }
1106             // Modern WebKit browsers are at least X-Grade
1107             m = ua.match( /AppleWebKit\/([^\s]*)/ );
1108             if ( m && m[1] ) {
1109                 o.webkit = numberify( m[1] );
1110 
1111                 // Mobile browser check
1112                 if ( / Mobile\//.test( ua ) ) {
1113                     o.mobile = "Apple"; // iPhone or iPod Touch
1114                 } else {
1115                     m = ua.match( /NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/ );
1116                     if ( m ) {
1117                         o.mobile = m[0]; // Nokia N-series, Android, webOS,
1118                         // ex:
1119                         // NokiaN95
1120                     }
1121                 }
1122 
1123                 var m1 = ua.match( /Safari\/([^\s]*)/ );
1124                 if ( m1 && m1[1] ) // Safari
1125                     o.safari = numberify( m1[1] );
1126                 m = ua.match( /Chrome\/([^\s]*)/ );
1127                 if ( o.safari && m && m[1] ) {
1128                     o.chrome = numberify( m[1] ); // Chrome
1129                 } else {
1130                     m = ua.match( /AdobeAIR\/([^\s]*)/ );
1131                     if ( m ) {
1132                         o.air = m[0]; // Adobe AIR 1.0 or better
1133                     }
1134                 }
1135             }
1136 
1137             if ( !o.webkit ) { // not webkit
1138                 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316;
1139                 // fi; U;
1140                 // try get firefox and it's ver
1141                 // ssr)
1142                 m = ua.match( /Opera[\s\/]([^\s]*)/ );
1143                 if ( m && m[1] ) {
1144                     o.opera = numberify( m[1] );
1145                     m = ua.match( /Opera Mini[^;]*/ );
1146                     if ( m ) {
1147                         o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
1148                     }
1149                 } else { // not opera or webkit
1150                     m = ua.match( /MSIE\s([^;]*)/ );
1151                     if ( m && m[1] ) {
1152                         o.ie = numberify( m[1] );
1153                     } else { // not opera, webkit, or ie
1154                         m = ua.match( /Gecko\/([^\s]*)/ );
1155                         if ( m ) {
1156                             o.gecko = 1; // Gecko detected, look for revision
1157                             m = ua.match( /rv:([^\s\)]*)/ );
1158                             if ( m && m[1] ) {
1159                                 o.gecko = numberify( m[1] );
1160                             }
1161                         }
1162                     }
1163                 }
1164             }
1165         }
1166 
1167         return o;
1168     }
1169         )
1170         (),
1171 
1172     /**
1173      * 提供队列方式执行用例的方案,接口包括start、add、next,方法全部执行完毕时会启动用例继续执行
1174      */
1175     functionListHelper:function () {
1176         var check = {
1177             list:[],
1178             start:function () {
1179                 var self = this;
1180                 $( this ).bind( 'next', function () {
1181                     setTimeout( function () {// 避免太深的堆栈
1182                         if ( self.list.length == 0 )
1183                             start();
1184                         else
1185                             self.list.shift()();
1186                     }, 0 );
1187                 } );
1188                 self.next();
1189             },
1190             add:function ( func ) {
1191                 this.list.push( func );
1192             },
1193             next:function ( delay ) {
1194                 var self = this;
1195                 if ( delay ) {
1196                     setTimeout( function () {
1197                         $( self ).trigger( 'next' );
1198                     }, delay );
1199                 } else
1200                     $( this ).trigger( 'next' );
1201             }
1202         };
1203         return check;
1204     },
1205     getHTML:function ( co ) {
1206         var div = document.createElement( 'div' ), h;
1207         if ( !co )
1208             return 'null';
1209         div.appendChild( co.cloneNode( true ) );
1210         h = div.innerHTML.toLowerCase();
1211 
1212         h = h.replace( /[\r\n\t\u200b\ufeff]/g, '' ); // Remove line feeds and tabs
1213         h = h.replace( / (\w+)=([^\"][^\s>]*)/gi, ' $1="$2"' ); // Restore
1214         // attribs on IE
1215         return h;
1216     },
1217     getChildHTML:function ( co ) {
1218 
1219         var h = co.innerHTML.toLowerCase();
1220 
1221         h = h.replace( /[\r\n\t\u200b\ufeff]/g, '' ); // Remove line feeds and tabs
1222         h = h.replace( / (\w+)=([^\"][^\s>]*)/gi, ' $1="$2"' ); // Restore attribs on IE
1223 
1224         return h.replace( /\u200B/g, '' );
1225     },
1226     getIndex:function ( node ) {
1227         var childNodes = node.parentNode.childNodes, i = 0;
1228         while ( childNodes[i] !== node )
1229             i++;
1230         return i;
1231     },
1232     checkResult:function ( range, sc, ec, so, eo, collapsed, descript ) {
1233         descript = descript ? descript : '';
1234         equal( range.collapsed, collapsed, "check collapsed --" + descript );
1235         ok( range.startContainer === sc, "check startContainer--" + descript );
1236         ok( range.endContainer === ec, "check endContainer--" + descript );
1237         equal( range.startOffset, so, "check startOffset--" + descript );
1238         equal( range.endOffset, eo, "check endOffset--" + descript );
1239     },
1240     manualDeleteFillData:function ( node ) {
1241             var childs = node.childNodes;
1242             for ( var i = 0; i < childs.length; i++ ) {
1243                 var fillData = childs[i];
1244                 if ( (fillData.nodeType == 3) && ( fillData.data == domUtils.fillChar ) ) {
1245                     domUtils.remove( fillData );
1246                     fillData = null;
1247                     
1248                 }
1249                 else
1250                     this.manualDeleteFillData( fillData );
1251             }
1252 
1253 
1254     },
1255     cssStyleToDomStyle:function ( cssName ) {
1256         var test = document.createElement( 'div' ).style,
1257             cssFloat = test.cssFloat != undefined ? 'cssFloat'
1258                 : test.styleFloat != undefined ? 'styleFloat'
1259                 : 'float',
1260             cache = { 'float':cssFloat };
1261 
1262         function replacer( match ) {
1263             return match.charAt( 1 ).toUpperCase();
1264         }
1265 
1266 //        return function( cssName ) {
1267         return cache[cssName] || (cache[cssName] = cssName.replace( /-./g, replacer ) );
1268 //        };
1269     },
1270     isSameStyle:function ( elementA, elementB ) {
1271         var styleA = elementA.style.cssText,
1272             styleB = elementB.style.cssText;
1273         if ( this.browser.ie && this.browser.version == 6 ) {
1274             styleA = styleA.toLowerCase();
1275             styleB = styleB.toLowerCase();
1276         }
1277         if ( !styleA && !styleB ) {
1278             return true;
1279         } else if ( !styleA || !styleB ) {
1280             return false;
1281         }
1282         var styleNameMap = {},
1283             record = [],
1284             exit = {};
1285         styleA.replace( /[\w-]+\s*(?=:)/g, function ( name ) {
1286             styleNameMap[name] = record.push( name );
1287         } );
1288         try {
1289             styleB.replace( /[\w-]+\s*(?=:)/g, function ( name ) {
1290                 var index = styleNameMap[name];
1291                 if ( index ) {
1292 //                    name = this.cssStyleToDomStyle( name );
1293                     if ( elementA.style[name] !== elementB.style[name] ) {
1294                         throw exit;
1295                     }
1296                     record[index - 1] = '';
1297                 } else {
1298                     throw exit;
1299                 }
1300             } );
1301         } catch ( ex ) {
1302             if ( ex === exit ) {
1303                 return false;
1304             }
1305         }
1306         return !record.join( '' );
1307     },
1308     hasSameAttrs:function ( nodeA, nodeB ) {
1309         if ( nodeA.tagName != nodeB.tagName )
1310             return 0;
1311         var thisAttribs = nodeA.attributes,
1312             otherAttribs = nodeB.attributes;
1313         if ( thisAttribs.length != otherAttribs.length )
1314             return 0;
1315         if ( thisAttribs.length == 0 )
1316             return 1;
1317         var attrA, attrB;
1318         for ( var i = 0; attrA = thisAttribs[i++]; ) {
1319             if ( attrA.nodeName == 'style' ) {
1320                 if ( this.isSameStyle( nodeA, nodeB ) ) {
1321                     continue
1322                 } else {
1323                     return 0;
1324                 }
1325             }
1326             if ( !ua.browser.ie || attrA.specified ) {
1327                 attrB = nodeB.attributes[attrA.nodeName];
1328                 if ( !attrB ) {
1329                     return 0;
1330                 }
1331             }
1332             return 1;
1333         }
1334         return 1;
1335     },
1336     /**
1337      *检查两个节点(包含所有子节点)是否具有相同的属性
1338      */
1339     flag:true,
1340     checkAllChildAttribs:function ( nodeA, nodeB ) {
1341         var k = nodeA.childNodes.length;
1342         if ( k != nodeB.childNodes.length )
1343             this.flag = false;
1344         if ( !this.flag )
1345             return this.flag;
1346         while ( k ) {
1347             var tmpNodeA = nodeA.childNodes[k - 1];
1348             var tmpNodeB = nodeB.childNodes[k - 1];
1349             k--;
1350 
1351             if ( tmpNodeA.nodeType == 3 || tmpNodeB.nodeType == 3 || tmpNodeA.nodeType == 8 || tmpNodeB.nodeType == 8 )
1352                 continue;
1353             if ( !this.hasSameAttrs( tmpNodeA, tmpNodeB ) ) {
1354                 this.flag = false;
1355                 break;
1356 
1357             }
1358 
1359             this.checkAllChildAttribs( tmpNodeA, tmpNodeB );
1360         }
1361         return this.flag;
1362     },
1363     haveSameAllChildAttribs:function ( nodeA, nodeB ) {
1364         this.flag = true;
1365         return this.checkAllChildAttribs( nodeA, nodeB );
1366     },
1367     /*查看传入的html是否与传入的元素ele具有相同的style*/
1368     checkHTMLSameStyle:function ( html, doc, ele, descript ) {
1369         var tagEle = doc.createElement( ele.tagName );
1370         tagEle.innerHTML = html;
1371         /*会有一些不可见字符,在比较前提前删掉*/
1372         this.manualDeleteFillData( ele );
1373         ok( this.haveSameAllChildAttribs( ele, tagEle ), descript );
1374 //        ok(this.equalsNode(ele.innerHMTL,html),descript);
1375     },
1376 
1377 
1378     equalsNode:function ( na, nb ) {
1379         function compare( nodeA, nodeB ) {
1380             if ( nodeA.nodeType != nodeB.nodeType ) {
1381                 return 0;
1382             }
1383             if ( nodeA.nodeType == 3 ) {
1384                 return  nodeA.nodeValue == nodeB.nodeValue
1385             }
1386             if ( domUtils.isSameElement( nodeA, nodeB ) ) {
1387                 if ( !nodeA.firstChild && !nodeB.firstChild ) {
1388                     return 1;
1389                 }
1390                 if ( nodeA.firstChild && !nodeB.firstChild || !nodeA.firstChild && nodeB.firstChild ) {
1391                     return 0
1392                 }
1393                 for ( var i = 0, ai, bi; ai = nodeA.childNodes[i], bi = nodeB.childNodes[i++]; ) {
1394 
1395                     if ( !compare( ai, bi ) ) {
1396                         return 0
1397                     }
1398                 }
1399                 return 1;
1400             } else {
1401                 return 0;
1402             }
1403         }
1404 
1405         return compare( domUtils.creElm( document, 'div', {
1406             'innerHTML':na
1407         } ), domUtils.creElm( document, 'div', {
1408             'innerHTML':nb
1409         } ) );
1410     },
1411 
1412 
1413     getSelectedText:function () {
1414         if ( window.getSelection ) {
1415             // This technique is the most likely to be standardized.
1416             // getSelection() returns a Selection object, which we do not document.
1417             return window.getSelection().toString();
1418         }
1419         else if ( document.getSelection ) {
1420             // This is an older, simpler technique that returns a string
1421             return document.getSelection();
1422         }
1423         else if ( document.selection ) {
1424             // This is the IE-specific technique.
1425             // We do not document the IE selection property or TextRange objects.
1426             return document.selection.createRange().text;
1427         }
1428     },
1429     findPosition:function ( oElement ) {
1430         var x2 = 0;
1431         var y2 = 0;
1432         var width = oElement.offsetWidth;
1433         var height = oElement.offsetHeight;
1434         if ( typeof( oElement.offsetParent ) != 'undefined' ) {
1435             for ( var posX = 0, posY = 0; oElement; oElement = oElement.offsetParent ) {
1436                 posX += oElement.offsetLeft;
1437                 posY += oElement.offsetTop;
1438             }
1439             x2 = posX + width;
1440             y2 = posY + height;
1441             return [ posX, posY , x2, y2];
1442 
1443         } else {
1444             x2 = oElement.x + width;
1445             y2 = oElement.y + height;
1446             return [ oElement.x, oElement.y, x2, y2];
1447         }
1448     },
1449 
1450     checkElementPath:function ( arr1, arr2, descript ) {
1451         if ( !descript )
1452             descript = '';
1453         var index = arr1.length;
1454         if ( index != arr2.length )
1455             ok( false, '路径深度不相同' );
1456         else {
1457 
1458             while ( index > 0 )
1459                 equal( arr1[--index ], arr2[index ], descript + '---第' + index + '个元素' + arr1[index] );
1460         }
1461     },
1462     getBrowser:function () {
1463         var browser = "";
1464         if ( this.browser.ie == 6 )
1465             browser = 'ie6';
1466         if ( this.browser.ie == 7 )
1467             browser = 'ie7';
1468         if ( this.browser.ie == 8 )
1469             browser = 'ie8';
1470         if ( this.browser.ie == 9 )
1471             browser = 'ie9';
1472         if ( this.browser.safari )
1473             browser = 'safari';
1474         if ( this.browser.firefox )
1475             browser = 'firefox';
1476         if ( this.browser.chrome )
1477             browser = 'chrome';
1478         if ( this.browser.maxthon ) {
1479             browser = 'maxthon';
1480         }
1481         if ( this.browser.maxthonIE )
1482             browser = 'maxIE';
1483         if ( this.browser.opera )
1484             browser = 'opera';
1485         return browser;
1486     },
1487     getFloatStyle:function ( ele ) {
1488         if ( this.browser.ie )
1489             return ele.style['styleFloat'];
1490         else
1491             return ele.style['cssFloat'];
1492     }
1493 
1494 
1495 };
1496 var ua = UserAction;
1497 var upath = ua.commonData.currentPath();
1498 var cpath = ua.commonData.datadir;